package com.huajx.core.server.impl;

import com.huajx.core.handler.ServerHandlerFactory;
import com.huajx.core.log.Log;
import com.huajx.core.server.HbootServer;
import com.huajx.core.server.config.HbootServerConfig;
import org.apache.mina.filter.codec.ProtocolCodecFactory;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LogLevel;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;

/**
 * HbootServer基础实现类
 */
public abstract class BaseTcpServer implements HbootServer {
    public static final int DEFAULT_PORT = 10041;

    private static final Logger logger = LoggerFactory.getLogger(BaseTcpServer.class);
    private boolean isRunning;

    private String serverName;
    private int port;

    private String describe;

    protected NioSocketAcceptor acceptor;

    /**
     * 处理适配器
     *
     * @return ServerHandlerFactory
     */
    protected abstract ServerHandlerFactory getHandler();

    /**
     * 编码处理工厂类
     *
     * @return ProtocolCodecFactory
     */
    protected abstract ProtocolCodecFactory getProtocolCodecFactory();

    /**
     * 初始化
     */
    protected abstract void initial();

    /**
     * 启动HTTP服务端箭筒HTTP请求
     *
     * @param port 要监听的端口号
     * @throws IOException
     */
    public void start(int port) throws IOException {
        synchronized (this) {
            if (isRunning) {
                logger.warn("服务器已经启动！");
                return;
            }

            if (port < 80) { //小于80端口
                port = DEFAULT_PORT;
            }

            acceptor = new NioSocketAcceptor();

            acceptor.getFilterChain().addLast("protocolFilter", new ProtocolCodecFilter(getProtocolCodecFactory()));

            setLoggerFilter();

            acceptor.setHandler(getHandler());

            initial();

            acceptor.setReuseAddress(true);
            acceptor.bind(new InetSocketAddress(port));
            isRunning = true;

            logger.info("{} 服务启动完毕，监听端口:{}, {}", serverName, port, describe);
        }
    }

    /**
     * 使用默认端口 8080
     */
    @Override
    public void start() {
        try {
            start(port);
        } catch (IOException e) {
            String msg = e.getMessage();
            if (msg.contains("Address already in use")) {
                stop();
            }
            logger.error("启动异常：{}", e.getMessage());
        }
    }

    /**
     * 停止监听HTTP服务
     */
    @Override
    public void stop() {
//		synchronized (this) {
        if (!isRunning) {
            if (acceptor.isActive()) {
                acceptor.unbind();
                acceptor.dispose();
            }
            logger.warn("{}服务器已经停止！", serverName);
            return;
        }
        isRunning = false;
        try {
            acceptor.unbind();
            acceptor.dispose();
            logger.info("{}服务器停止成功！", serverName);
        } catch (Exception e) {
            e.printStackTrace();
        }
//		}
    }

    @Override
    public boolean isRunning() {
        return isRunning;
    }

    @Override
    public void config(HbootServerConfig config) {
        this.port = config.getPort() <= 80 ? DEFAULT_PORT : config.getPort();
        this.serverName = config.getName();
        this.describe = config.getDescribe();
//        setEncoding(StrUtil.isBlank(config.getEncoding()) ? CharsetUtil.UTF_8 : config.getEncoding());
    }

    /**
     * 设置日志过滤级别
     */
    protected void setLoggerFilter() {
        LogLevel level = LogLevel.DEBUG;

        if (logger.isTraceEnabled()) {
            level = LogLevel.TRACE;
        } else if (logger.isDebugEnabled()) {
            level = LogLevel.DEBUG;
        } else if (logger.isInfoEnabled()) {
            level = LogLevel.DEBUG;
        } else if (logger.isWarnEnabled()) {
            level = LogLevel.INFO;
        } else if (logger.isErrorEnabled()) {
            level = LogLevel.INFO;
        }

        LoggingFilter loggingFilter = new LoggingFilter();

        loggingFilter.setMessageReceivedLogLevel(level);
        loggingFilter.setMessageSentLogLevel(level);
        loggingFilter.setSessionOpenedLogLevel(level);
        loggingFilter.setSessionCreatedLogLevel(level);
        loggingFilter.setSessionIdleLogLevel(level);
        loggingFilter.setSessionClosedLogLevel(level);

        acceptor.getFilterChain().addLast("logger", loggingFilter);
    }
}
